#include "D3DMesh.h"
#include "ShaderGroup.h"
#include "Texture.h"
#include <vector>

D3DMesh::D3DMesh()
{
	m_pVertexBuffer = 0;
	m_pIndexBuffer = 0;
	m_nNumIndicies = 0;
	m_nNumVerts = 0;

}


D3DMesh::~D3DMesh()
{
}

HRESULT D3DMesh::Initizalize(ID3D11Device* device, const char* objPath, const char* texturePath, bool isSkyBox)
{
	HRESULT hr;

	hr = LoadMeshFromObjFile(device, objPath, isSkyBox);
	if (hr != S_OK)
		return hr;
	hr = LoadTexture(device, texturePath);
	return hr;
}


HRESULT D3DMesh::LoadMeshFromObjFile(ID3D11Device* device, const char* path, bool isSkyBox)
{
		std::vector< unsigned int > vertexIndices, uvIndices, normalIndices;
		std::vector< XMFLOAT3 > temp_vertices;
		std::vector< XMFLOAT2 > temp_uvs;
		std::vector< XMFLOAT3 > temp_normals;
		std::vector< VERTEX > finalVerts;

		FILE * file;
		fopen_s(&file, (const char*)path, "r");
	
	
		while (1){
	
			char lineHeader[128];
			// read the first word of the line
			int res = fscanf_s(file, "%s", lineHeader, _countof(lineHeader));
			if (res == EOF)
				break; // EOF = End Of File. Quit the loop.
	
			// else : parse lineHeader
			if (strcmp(lineHeader, "v") == 0)
			{
				XMFLOAT3 vertex;
				fscanf_s(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
				vertex.z *= -1.0f;
				temp_vertices.push_back(vertex);
			}
			else if (strcmp(lineHeader, "vt") == 0)
			{
				XMFLOAT2 uv;
				fscanf_s(file, "%f %f\n", &uv.x, &uv.y);
				uv.y = 1.0f - uv.y;
				temp_uvs.push_back(uv);
			}
			else if (strcmp(lineHeader, "vn") == 0)
			{
				XMFLOAT3 normal;
				fscanf_s(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
				normal.z *= -1.0f;
				temp_normals.push_back(normal);
			}
			else if (strcmp(lineHeader, "f") == 0)
			{
				std::string vertex1, vertex2, vertex3;
				unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
				int matches = fscanf_s(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
				
					vertexIndices.push_back(vertexIndex[2]);
					vertexIndices.push_back(vertexIndex[1]);
					vertexIndices.push_back(vertexIndex[0]);
					uvIndices.push_back(uvIndex[2]);
					uvIndices.push_back(uvIndex[1]);
					uvIndices.push_back(uvIndex[0]);
					normalIndices.push_back(normalIndex[2]);
					normalIndices.push_back(normalIndex[1]);
					normalIndices.push_back(normalIndex[0]);
				
				
			}
		}
	
		VERTEX temp;
		m_nNumIndicies = vertexIndices.size();
		m_nNumVerts = vertexIndices.size();


		for (unsigned int i = 0; i < m_nNumIndicies; i++)
		{
			unsigned int vertIndex = vertexIndices[i];
			unsigned int uvIndex = uvIndices[i];
			unsigned int normalIndex = normalIndices[i];
	
			
			temp.normal = temp_normals[normalIndex - 1];
			temp.uv = temp_uvs[uvIndex - 1];
			temp.pos = temp_vertices[vertIndex - 1];
			temp._color = { 0.0f, 1.0f, 0.0f, 1.0f };
	
			finalVerts.push_back(temp);
			
		}
		XMMATRIX mat = XMMatrixIdentity(); 
		XMStoreFloat4x4(&matrix, mat);
		//Star Buffer
		D3D11_BUFFER_DESC bufferDesc;
		ZeroMemory(&bufferDesc, sizeof(bufferDesc));
		bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
		bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		bufferDesc.CPUAccessFlags = NULL;
		bufferDesc.ByteWidth = sizeof(VERTEX) * finalVerts.size();
	
		D3D11_SUBRESOURCE_DATA subSourceData;
		ZeroMemory(&subSourceData, sizeof(subSourceData));
		subSourceData.pSysMem = &finalVerts[0];
	
		
	
		HRESULT hr = device->CreateBuffer(&bufferDesc, &subSourceData, &m_pVertexBuffer);
	
		
		return hr;
}
HRESULT D3DMesh::CreateFromVectors(ID3D11Device* device, VERTEX* verts, unsigned int* indicies, unsigned int numVerts, unsigned int numInd, XMFLOAT4 color, const char* textureFile)
{

	XMMATRIX mat = XMMatrixIdentity();
	XMStoreFloat4x4(&matrix, mat);
	D3D11_BUFFER_DESC bufferDesc;
	ZeroMemory(&bufferDesc, sizeof(bufferDesc));
	bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
	bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bufferDesc.CPUAccessFlags = NULL;
	bufferDesc.ByteWidth = sizeof(VERTEX) * numVerts;

	D3D11_SUBRESOURCE_DATA subSourceData;
	ZeroMemory(&subSourceData, sizeof(subSourceData));
	subSourceData.pSysMem = &verts[0];

	HRESULT hr = device->CreateBuffer(&bufferDesc, &subSourceData, &m_pVertexBuffer);
	 m_nNumIndicies = numInd;
	 m_nNumVerts = numVerts;
	 if (m_nNumIndicies)
	 {
		 D3D11_BUFFER_DESC indexBufferDesc;
		 ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));
		 indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
		 indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
		 indexBufferDesc.CPUAccessFlags = NULL;
		 indexBufferDesc.ByteWidth = sizeof(unsigned int) * numInd;


		 D3D11_SUBRESOURCE_DATA indexSubSourceData;
		 ZeroMemory(&indexSubSourceData, sizeof(indexSubSourceData));
		 indexSubSourceData.pSysMem = &indicies[0];

		 hr = device->CreateBuffer(&indexBufferDesc, &indexSubSourceData, &m_pIndexBuffer);
	 }

	if (textureFile)
		hr = LoadTexture(device, textureFile);
	return hr;
}

HRESULT D3DMesh::LoadTexture(ID3D11Device* device, const char* path)
{
	HRESULT hr = m_pTexture.LoadTexutureToShaderResource(device, path);
	return hr;
}
void D3DMesh::Render(ID3D11DeviceContext* pContext, ShaderGroup* shader, VS_CONSTANT_BUFFER* vsConstBufferInfo, DIR_LIGHT_BUFFER* dlbufferInfo, POINT_LIGHT_BUFFER* plbufferInfo, SPOT_LIGHT_BUFFER* slbufferInfo, float dt)
{
		//Set up constant buffers for vertex shaders
	//XMMATRIX matrix = XMLoadFloat4x4(&vsConstBufferInfo->world);
	//
	//	XMMATRIX rotation = XMMatrixRotationY(dt);
	//
	//	matrix = XMMatrixMultiply(rotation, matrix);
	
		
		UINT  strides = sizeof(VERTEX);
		UINT  offsets = 0;
		pContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &strides, &offsets);


		shader->SetVShaderInfo(pContext, vsConstBufferInfo);
		shader->SetGShaderInfo(pContext, vsConstBufferInfo);
		shader->SetPShaderInfo(pContext, m_pTexture.GetTexture(), dlbufferInfo, plbufferInfo, slbufferInfo);
		shader->AddShadersToPipeline(pContext);
	

		pContext->Draw(m_nNumVerts, 0);
}
void D3DMesh::RenderIndexed(ID3D11DeviceContext* pContext, ShaderGroup* shader, VS_CONSTANT_BUFFER* vsConstBufferInfo, DIR_LIGHT_BUFFER* dlbufferInfo, POINT_LIGHT_BUFFER* plbufferInfo, SPOT_LIGHT_BUFFER* slbufferInfo, float dt)
{
	

	UINT  strides = sizeof(VERTEX);
	UINT  offsets = 0;
	pContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &strides, &offsets);
	pContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, offsets);


	shader->SetVShaderInfo(pContext, vsConstBufferInfo);
	shader->SetPShaderInfo(pContext, m_pTexture.GetTexture(), dlbufferInfo, plbufferInfo, slbufferInfo);
	shader->SetGShaderInfo(pContext, vsConstBufferInfo);
	shader->AddShadersToPipeline(pContext);

	pContext->DrawIndexed(m_nNumIndicies, 0, 0);


}


void D3DMesh::ShutDown()
{
	if (m_pVertexBuffer)
	{
		m_pVertexBuffer->Release();
		m_pVertexBuffer = 0;
	}
	if (m_pIndexBuffer)
	{
		m_pIndexBuffer->Release();
		m_pIndexBuffer = 0;
	}
	
	m_pTexture.ShutDown();
	
}

void D3DMesh::SetWorldMatrix(XMFLOAT4X4 newMatrix)
{
	matrix = newMatrix;
}